home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 / Ham Radio 2000.iso / ham2000 / packet / monax25 / stats.c < prev    next >
Text File  |  1987-10-22  |  23KB  |  1,130 lines

  1. /*
  2.     stats.c - monitor AX.25 channel and gather network performance
  3.           statistics.
  4.  
  5.    Hardware: IBM PC or compatable with at least 1 serial port,
  6.              TNC with "KISS" firmware installed.
  7.  
  8.    Other software: W0RLI or WA7MBL compatable serial BIOS such
  9.            as COMBIOS or MBBIOS.  KISS software for
  10.                    TNC.
  11.                   
  12.    Language = Microsoft C version 4.0, Microsoft Macro Assembler version 4.0
  13.  
  14.  
  15.    This source is distributed freely and may be copied and
  16.    redistributed with the following provisos:
  17.    
  18.            You may not sell it, nor may you charge for making 
  19.            copies beyond the actual cost of mailing and media.
  20.                       
  21.    Written by Skip Hansen WB6YMH and Harold Price NK6K.
  22.  
  23.    Feedback is desired.
  24.  
  25.    RCP/M (213) 541-2503 300/1200/2400 baud
  26.    or via packet WB6YMH @ WB6YMH-2 or 
  27.          NK6K @ NK6K
  28.  
  29.    Modification history:
  30.  
  31.     8/10/87         WB6YMH: Initial release.    
  32.     ver 1.0         
  33.  
  34.    10/18/87     First general release.
  35.    ver 1.1
  36.  
  37. */
  38.  
  39. #include <stdio.h>
  40. #include <time.h>
  41. #include <dos.h>
  42. #include "monfile.h"
  43.  
  44. /* configuration constants */
  45.  
  46. #define    DUMP_INTERVAL    60*5    /* number of seconds between table dumps */
  47. #define MAX_CIRCUIT     200    /* number of entrys in circuit table     */
  48. #define MAX_DIGIS     100    /* number of entrys in digi table     */
  49.  
  50. /* misc constants */
  51.  
  52. #define FALSE     0
  53. #define TRUE     !FALSE
  54.  
  55. #define FEND    0300
  56. #define FESC    0333
  57. #define TFEND    0334
  58. #define    TFESC    0335
  59.  
  60. #define MIN_SIZE    17    /* minimum size of valid ax.25 frame */
  61. #define MAX_SIZE    330    /* maximum size of a valid frame */
  62.  
  63.  
  64. /* global variables */
  65.  
  66. union   REGS inregs, outregs;
  67.  
  68. unsigned char frame_buf[1024];    /* incomming SLIP frame is assembled here */
  69.  
  70. int frame_size;        /* number of bytes in frame, including CRC */
  71.  
  72. unsigned char *cp,c;    
  73.  
  74. unsigned char getbyte();
  75.  
  76. unsigned long get_cd_active();    /* assembly interrupt routines */
  77. unsigned long get_cd_inactive();
  78.  
  79. /* NET/ROM network header */
  80.  
  81. struct netrom {
  82.     char org_node[7];
  83.     char dest_node[7];
  84.     unsigned char ttl;
  85.     unsigned char cndx;
  86.     unsigned char cid;
  87.     unsigned char tx;
  88.     unsigned char rx;
  89.     unsigned char opcode;
  90.     union{
  91.         struct {
  92.             unsigned char p_wind;
  93.             char user[7];
  94.             char at_node[7];
  95.         } con;
  96.  
  97.         struct {
  98.             unsigned char a_wind;
  99.         } con_ack;
  100.  
  101.         struct {
  102.             char info[236];
  103.         } i;
  104.     } v;
  105. };
  106.  
  107. struct netrom *netp;
  108.  
  109. /* NET/ROM routing table broadcast structure */
  110.  
  111. struct node_list{
  112.     unsigned char signature;
  113.     char mnemonic[6];
  114.     struct routes{
  115.         char dest_node[7];
  116.         char dest_mnemonic[6];
  117.         char best_neighbor[7];
  118.         unsigned char best_quality;
  119.     } route[11];
  120. };
  121.  
  122. struct node_list *uip;
  123.  
  124. /* circuit table */
  125.  
  126. struct CIRCUIT_RECORD ctab[MAX_CIRCUIT];
  127.  
  128. /* digipeater table */
  129.  
  130. struct DIGI_RECORD dtab[MAX_DIGIS];
  131.  
  132. /* frequency wide statistics */
  133.  
  134. struct FREQ_RECORD freq;
  135.  
  136. /* misc variable used to trace state of circuit */
  137.  
  138. struct STATE_TABLE{
  139.     unsigned int n[8];        /* array of checksums of i frames by n(s) */
  140.     unsigned int digi_bits[8];    /* heard digipeater bit field */
  141.     unsigned int last_ui;        /* checksum of last ui frame */
  142.     unsigned int ui_bits;        /* heard digipeater bit field for ui */
  143.     unsigned int s_bits;        /* heard digipeater bit fields for s */
  144.     unsigned char last_ns;        /* last n(s) we heard */
  145.     unsigned char last_s;        /* last control field we heard */
  146.     unsigned char first_digi;    /* first digipeater we heard */
  147. } stab[MAX_CIRCUIT];
  148.  
  149.  
  150. int    nr_circuits;        /* number of active entrys in circuit table */
  151.  
  152. unsigned int    nr_digis;    /* number of active entrys in digipeater table */
  153.  
  154. unsigned char     digi_num;    /* number of digi current frame was heard from */
  155.  
  156. int    nr_digi;        /* total number of digis this connection */
  157.  
  158. unsigned int    cnum;        /* circuit number of current frame      */
  159.  
  160. unsigned int    dnum;          /* circuit number of current frame for   */
  161.                 /* "non-digipeated" counters         */
  162.  
  163. unsigned int    i_size;        /* size of data portion of UI or I frame */
  164.  
  165. char    retry;            /* retry flag */
  166.  
  167. char    last_c;            /* last character sent to screen */
  168.  
  169. unsigned char crtype;        /* command/response flag */
  170.  
  171. unsigned char n_s;
  172.  
  173. unsigned int isum;        /* checksum of data portion of UI or I frame */
  174.  
  175. unsigned int digi_bit;        /* bit representing current hop */
  176.  
  177. unsigned long write_time,start_time;
  178.  
  179.  
  180. /* parser variables */
  181.  
  182. int p_timestamp=0;
  183. int p_baud=4800;
  184. int p_port=0;        /* COM1 */
  185. int port_base = 0x3f8;    /* COM1 */
  186. char using_combios;
  187. char ints_active;
  188.  
  189. main (argc, argv)
  190. int    argc;
  191. char    *argv[];
  192. {
  193.     unsigned char to[10],from[10];
  194.     long cur_time;
  195.     int i,j;
  196.     unsigned char s[128];
  197.  
  198.  
  199.     printf("STATS version 1.1 - Packet radio network performance monitoring program\n");
  200.     printf("October 1987, written by WB6YMH and NK6K\n\n");
  201.     printf("Type ALT-C for command prompt.\n\n");
  202.  
  203.     if (argc>1) {    /* package up command line args for parser */
  204.         j=0;
  205.         for (i=1;i<argc;i++) {
  206.             while(*argv[i]!='\0') {
  207.                 s[j]=*argv[i];
  208.                 j++;
  209.                 *argv[i]++;
  210.             }
  211.             s[j++]=' ';
  212.         }
  213.         s[j-1]='\0';    
  214.         parse(1,s);
  215.     }
  216.  
  217.     /* check for presence of COMBIOS for our com port */
  218.  
  219.     inregs.h.ah = 4;    /* Inquiry */
  220.     inregs.x.dx = p_port;
  221.     int86(0x14,&inregs,&outregs);
  222.     if(outregs.x.ax == 0xaa55){
  223.         ints_active = FALSE;
  224.         using_combios = TRUE;
  225.     }
  226.     else{
  227.         if(p_port < 0 || p_port > 1){
  228.             printf("Error: Port number must be COM1 or COM2 unless COMBIOS is loaded.\n");
  229.             exit(1);
  230.         }
  231.         serlinit(p_port);
  232.         using_combios = FALSE;
  233.         ints_active = TRUE;
  234.     }
  235.  
  236.     if(p_port){
  237.         set_base(0x2f8);    /* com2 */
  238.     }
  239.     else{
  240.         set_base(0x3f8);    /* com1 */
  241.     }
  242.  
  243.     tick_init();
  244.  
  245.     nr_circuits = 0;
  246.     time(&start_time);
  247.     write_time = start_time + DUMP_INTERVAL;
  248.     init_freq();
  249.  
  250.     while(1){
  251.         if(kbhit()) 
  252.             do_kbhit();
  253.  
  254.         /* get a frame, check for reasonable frame size  */
  255.         /* Some versions of KISS seem to pass bad frames */
  256.         /* once in a while which drives the monitoring   */
  257.         /* code nuts if the frame is a runt.             */
  258.  
  259.         do{
  260.             get_frame();
  261.  
  262.         } while( frame_size < MIN_SIZE || frame_size > MAX_SIZE); 
  263.  
  264.         cp=&frame_buf[1];    /* skip SLIP type byte */
  265.  
  266.         /* put a null at the end of the frame for convience */
  267.  
  268.         cp[frame_size-2]=0;
  269.  
  270.         freq.t_packets++;
  271.         freq.t_bytes += frame_size;    
  272.  
  273.         if(frame_size <= 32)
  274.             freq.l32++;
  275.         else if(frame_size <=64)
  276.             freq.l64++;
  277.         else if(frame_size <= 128)
  278.             freq.l128++;
  279.         else if(frame_size <= 256)
  280.             freq.l256++;
  281.         else
  282.             freq.g256++;
  283.  
  284.         if (p_timestamp) {
  285.             time(&cur_time);
  286.             printf("[%15.15s] ",ctime(&cur_time)+4);
  287.         }
  288.         pcall(cp+7,0);
  289.         bcall(cp+7,from);
  290.         putchar('>');
  291.         pcall(cp,0);
  292.         bcall(cp,to);
  293.  
  294.         /* check for ax25v1 vs ax25v2 */
  295.  
  296.         if ((cp[6] & 0x80) == (cp[13] & 0x80))
  297.             crtype='o';
  298.         else if (cp[6] & 0x80)
  299.             crtype='c';
  300.         else
  301.             crtype='r';
  302.  
  303.         cp+=7;
  304.  
  305.         /* print the digipeater list */
  306.  
  307.         nr_digi = 0;
  308.         digi_num = 0;
  309.         digi_bit = 1;
  310.         while(!(cp[6] & 1)){
  311.             putchar(',');
  312.             nr_digi++;
  313.             pcall(cp+7,1);
  314.             if(cp[13] & 0x80  && (cp[13] & 1  || !(cp[20] & 0x80))){
  315.                 do_digi(cp+7);    /* update digi record */
  316.                 digi_bit = 1 << nr_digi;
  317.                 digi_num = nr_digi;
  318.             }                
  319.             cp+=7;
  320.         }
  321.         cp+=7;
  322.  
  323.         /* lookup this circuit in the tables */
  324.  
  325.         find_circuit(from,to);
  326.  
  327.         /* The global variable cnum points to current circuit.       */
  328.  
  329.         ctab[cnum].t_packets++;
  330.         ctab[cnum].t_bytes += frame_size;
  331.  
  332.         if(*cp & 0x10) {    /* p/f bit set */
  333.             if(crtype == 'c')
  334.                 ctab[dnum].poll++;
  335.             else if(crtype == 'r')
  336.                 ctab[dnum].final++;
  337.         }
  338.  
  339.         /* Decode control field of frame to find frame type */
  340.  
  341.         if(!(*cp & 1)){
  342.             do_iframe();
  343.         }
  344.         else if((*cp & 0xef) == 3){
  345.             do_ui();
  346.         }
  347.         else{
  348.             do_stype();
  349.         }
  350.  
  351.         if(last_c != 0xd)    /* prevent doublespaced output */
  352.             printf("\n");
  353.         last_c = 0;
  354.  
  355.         /* The global variable dnum points to current circuit if  */
  356.         /* and only if this is a "non-digipeated" frame otherwise */
  357.         /* dnum points to an unused entry in the table.  This      */
  358.         /* kluge helps to eliminate the need for tons of if       */
  359.         /* statements.                              */
  360.  
  361.         ctab[dnum].nd_packets++;
  362.         ctab[dnum].nd_bytes += frame_size;
  363.  
  364.         /* now a few sanity checks */
  365.  
  366.         if(ctab[cnum].u_dbytes > ctab[cnum].nd_dbytes){
  367.             printf("\007Error: U_dbytes > nd_dbytes!\n");
  368.         }
  369.         if(ctab[cnum].t_dbytes > ctab[cnum].t_bytes){
  370.             printf("\007Error: T_dbytes > t_bytes!\n");
  371.         }
  372.     }
  373. }
  374.  
  375. do_iframe()
  376. {
  377.     do_i_size();    /* Calculate size of data portion and checksum */ 
  378.  
  379.     printf("{%d,%d,%c",(*cp & 0xe0) >> 5,n_s=(*cp & 0xe) >> 1,
  380.         crtype);
  381.     if(*cp & 0x10) 
  382.         putchar('*');
  383.     cp++;    /* point to pid */
  384.     ctab[cnum].pid = *cp;
  385.     if(stab[cnum].last_ns == n_s  || /* expected n(s) */
  386.                      /*  - or -       */
  387.        stab[cnum].n[n_s] != isum){     /* different i   */
  388.                      /* than last time*/
  389.         stab[cnum].last_ns = (n_s + 1) & 0x7;
  390.         stab[cnum].n[n_s] = isum;
  391.         stab[cnum].digi_bits[n_s] = 0;
  392.         ctab[cnum].u_dpackets++;
  393.         ctab[cnum].u_dbytes += i_size;
  394.  
  395.         freq.u_packets++;
  396.         freq.u_bytes += frame_size;
  397.         if(i_size <= 32)
  398.             ctab[cnum].l32++;
  399.         else if(i_size <= 64)
  400.             ctab[cnum].l64++;
  401.         else if(i_size <= 128)
  402.             ctab[cnum].l128++;
  403.         else if(i_size <=256)
  404.             ctab[cnum].l256++;
  405.         else
  406.             ctab[cnum].g256++;
  407.     }
  408.  
  409.     do_bitmap(&stab[cnum].digi_bits[n_s]);
  410.  
  411.     ctab[dnum].i++;
  412.     ctab[cnum].t_dpackets++;
  413.     ctab[dnum].nd_dpackets++;
  414.     ctab[cnum].t_dbytes += i_size;
  415.     ctab[dnum].nd_dbytes += i_size;
  416.  
  417.     if(retry)
  418.         printf(",retry");
  419.  
  420.     putchar('}');
  421.  
  422.     if(*cp == 0xcf)        /* check for netrom PID */
  423.         do_netrom();
  424.     else
  425.         cp++;        /* skip PID */
  426.  
  427.     /* print data portion of frame */
  428.  
  429.     while(*cp){
  430.         last_c = *cp;
  431.         if( (*cp & 0x7f) != 7)
  432.             putchar(*cp);
  433.         if(*cp == 0xd)
  434.             putchar(0xa);
  435.         cp++;
  436.     }
  437. }
  438.  
  439. do_ui()
  440. {
  441.     do_i_size();    /* Calculate size of data portion and checksum */
  442.  
  443.     do_bitmap(&stab[cnum].s_bits);
  444.  
  445.     printf("{ui,%c",crtype);
  446.     if(*cp & 0x10)
  447.         putchar('*');
  448.  
  449.     if(stab[cnum].last_ui != isum){
  450.  
  451.     /* unique frame if checksums is different than last UI frame */
  452.  
  453.         stab[cnum].s_bits = 0;
  454.         freq.u_packets++;
  455.         ctab[cnum].u_dpackets++;
  456.         ctab[cnum].u_dbytes += i_size;
  457.         ctab[dnum].nd_dbytes += i_size;
  458.  
  459.         freq.u_bytes += frame_size;
  460.         stab[cnum].last_ui = isum;
  461.         if(i_size <= 32)
  462.             ctab[cnum].l32++;
  463.         else if(i_size <= 64)
  464.             ctab[cnum].l64++;
  465.         else if(i_size <= 128)
  466.             ctab[cnum].l128++;
  467.         else if(i_size <=256)
  468.             ctab[cnum].l256++;
  469.         else
  470.             ctab[cnum].g256++;
  471.     }
  472.  
  473.     if(retry)
  474.         printf(",retry");
  475.  
  476.     putchar('}');
  477.  
  478.     cp++;        /* point to pid */
  479.     ctab[cnum].pid = *cp;
  480.     switch(*cp){
  481.         case 0xcf:
  482.             /* net/rom node list broadcast */
  483.             do_routes();
  484.             break;
  485.  
  486.         case 0xcc:
  487.             /* ip frames */
  488.             do_ip();
  489.             break;
  490.  
  491.         case 0xcd:
  492.             /* arp frames */
  493.             do_arp();
  494.             break;
  495.  
  496.         case 0xf0:                        
  497.             /* "normal" ui frames */
  498.             cp++;        /* skip pid */    
  499.             while(*cp){
  500.                 last_c = *cp;
  501.                 if( (*cp & 0x7f) != 7)
  502.                     putchar(*cp);
  503.                 if(*cp == 0xd)
  504.                     putchar(0xa);
  505.                 cp++;
  506.             }
  507.             break;
  508.         default:
  509.             printf("Unknown PID in ui frame: 0x%02X\n",*cp);
  510.             break;
  511.     }
  512.  
  513.     ctab[dnum].ui++;
  514.     ctab[cnum].t_dpackets++;
  515.     ctab[dnum].nd_dpackets++;
  516.     ctab[cnum].t_dbytes += i_size;
  517. }
  518.  
  519. do_stype()
  520. {
  521.     if(stab[cnum].last_s != *cp){
  522.  
  523.     /* unique frame if control field is different than last frame */
  524.  
  525.         stab[cnum].last_s = *cp;
  526.         stab[cnum].s_bits = 0;
  527.         freq.u_packets++;
  528.         freq.u_bytes += frame_size;
  529.     }
  530.  
  531.     do_bitmap(&stab[cnum].s_bits);
  532.  
  533.     switch(*cp & 0x3){    
  534.         case 1:        /* S type frames */
  535.             switch((*cp & 0xc) >> 2){
  536.                 case 0:
  537.                     ctab[dnum].rr++;
  538.                     printf("{rr,%d",(*cp & 0xc0) >> 5);
  539.                     break;
  540.                 case 1:
  541.                     printf("{rnr,%d",(*cp & 0xc0) >> 5);
  542.                     ctab[dnum].rnr++;
  543.                     break;
  544.                 case 2:
  545.                     printf("{rej,%d",(*cp & 0xc0) >> 5);
  546.                     ctab[dnum].rej++;
  547.                     break;
  548.                 default:
  549.                     printf("{unknown S type ctrl: 0x%X}",*cp);
  550.                     return;
  551.                     break;
  552.             }
  553.             break;
  554.         case 0x3:        /* U frame types */
  555.                     /* UI frames handled elsewhere */
  556.             switch(*cp & 0xef){
  557.                 case 0x2f:
  558.                     printf("{sabm");
  559.                     ctab[dnum].sabm++;
  560.                     break;
  561.                 case 0x43:
  562.                     printf("{disc");
  563.                     ctab[dnum].disc++;
  564.                     break;
  565.                 case 0xf:
  566.                     printf("{dm");
  567.                     ctab[dnum].dm++;
  568.                     break;
  569.                 case 0x63:
  570.                     printf("{ua");
  571.                     ctab[dnum].ua++;
  572.                     break;
  573.                 case 0x87:
  574.                     printf("{frmr!");
  575.                     ctab[dnum].frmr++;
  576.                     break;
  577.                 default:
  578.                     printf("{unknown frame type ctrl: 0x%02X}",*cp);
  579.                     return;
  580.             }
  581.             break;
  582.         default:
  583.             printf("{unknown frame type ctrl: 0x%02X}",*cp);
  584.             return;
  585.             break;
  586.     }
  587.     printf(",%c",crtype);
  588.     if(*cp & 0x10)
  589.         putchar('*');
  590.  
  591.     if(retry)
  592.         printf(",retry");
  593.  
  594.     putchar('}');
  595. }
  596.  
  597. /*
  598.     Decode and print NET/ROM network header
  599. */
  600.  
  601. do_netrom()
  602. {
  603.     int     i;
  604.  
  605.     cp++;    /* point to network header */
  606.     netp = (struct netrom *) cp;
  607.     printf("\n{netrom>");
  608.     pcall(netp->org_node);
  609.     putchar('>');
  610.     pcall(netp->dest_node);
  611.     printf(", ttl:%d, cndx:%d, ",netp->ttl,netp->cndx);
  612.     printf("cid:%d, tx:%d, rx:%d",netp->cid,netp->tx,netp->rx);
  613.     if(netp->opcode & 0x80)
  614.         printf(", Choke");
  615.     if(netp->opcode & 0x40)
  616.         printf(", Nak");
  617.     if(netp->opcode & 0x20)
  618.         printf(", More");
  619.     if(netp->opcode & 0x10)
  620.         printf(", Rsvd");
  621.     switch(netp->opcode & 0xf){
  622.         case 1:
  623.             printf(", Conn");
  624.             printf(", win:%d}\nuser:",netp->v.con.p_wind);
  625.             pcall(netp->v.con.user);
  626.             printf(" node:");
  627.             pcall(netp->v.con.at_node);
  628.             *cp = 0;
  629.             break;
  630.         case 2:
  631.             printf(", Conack");
  632.             printf(", win:%d}",netp->v.con_ack.a_wind);
  633.             *cp = 0;
  634.             break;
  635.         case 3:
  636.             printf(", Discon}");
  637.             *cp = 0;
  638.             break;
  639.         case 4:
  640.             printf(", Disack}");
  641.             *cp = 0;
  642.             break;
  643.         case 5:
  644.             printf(", iframe}\n");
  645.             cp = netp->v.i.info;
  646.             break;
  647.         case 6:
  648.             printf(", iack}");
  649.             *cp = 0;
  650.             break;
  651.         default:
  652.             printf("unknown opcode 0x%2X",netp->opcode);
  653.             printf("\n");
  654.             for(i=0; i< 13; i++)
  655.                 printf("%x ",cp[i]);
  656.             printf("\n");
  657.             *cp = 0;
  658.             break;
  659.     }
  660. }
  661.  
  662. /*
  663.         Decode and print NET/ROM routing broadcast
  664. */
  665.  
  666. do_routes()
  667. {
  668.     int i, nr_nodes;
  669.  
  670.     cp++;
  671.     uip = (struct node_list *) cp;
  672.     if(uip->signature != 0xff){
  673.         printf("Routing broadcast with unknown signature: 0x%02X\n",uip->signature);
  674.         return;
  675.     }
  676.  
  677.     /* calculate number of nodes in this frame */
  678.  
  679.     nr_nodes = (frame_size - 19) / sizeof(struct routes);
  680.         
  681.     printf("Routing table broadcast from ");
  682.     p_mnem(uip->mnemonic);
  683.     printf("\n");
  684.  
  685.     for(i=0; i < nr_nodes; i++){
  686.         p_mnem(uip->route[i].dest_mnemonic);
  687.         putchar(':');
  688.         pcall(uip->route[i].dest_node);
  689.         printf(" via ");
  690.         pcall(uip->route[i].best_neighbor);
  691.         printf(" quality: %d\n",uip->route[i].best_quality);
  692.     }
  693. }
  694.  
  695. /*
  696.     Get a frame from the SLIP interface.
  697.     NOTE: leading type byte IS transfered into the buffer
  698. */
  699.  
  700. get_frame()
  701. {
  702.     char *bptr;
  703.     
  704.     bptr = frame_buf;
  705.     while(getbyte() != FEND);    /* wait for start of frame */
  706.     while( (c = getbyte()) == FEND);    /* ignore any extra FENDS */ 
  707.     frame_size = 0;
  708.     do{
  709.         if(c == FESC){
  710.             c = getbyte();
  711.             switch(c){
  712.                 case TFEND:
  713.                     *bptr++ = FEND;
  714.                     frame_size++;
  715.                     break;
  716.  
  717.                 case TFESC:
  718.                     *bptr++ = FESC;
  719.                     frame_size++;
  720.                     break;
  721.  
  722.                 default:
  723.                     break;
  724.             }
  725.         }
  726.         else{
  727.             *bptr++ = c;
  728.             frame_size++;
  729.         }
  730.         c = getbyte();
  731.     } while( c != FEND);
  732.  
  733.     /* adjust for CRC bytes which are not transfered */
  734.  
  735.     frame_size++;        
  736. }
  737.  
  738. /*
  739.     Get a byte from the serial line
  740. */
  741.  
  742. unsigned char getbyte()
  743. {
  744.     int x,not_ready;
  745.  
  746.     do{
  747.         if(kbhit())
  748.             do_kbhit();
  749.         if(time(0) >= write_time)
  750.             dump_data();
  751.         if(using_combios){
  752.             inregs.h.ah = 3;    /* get com port status */
  753.             inregs.x.dx = p_port;
  754.             int86(0x14,&inregs,&outregs);
  755.             not_ready = !(outregs.h.ah & 1);
  756.         }
  757.         else{
  758.             x = rcvbyte();
  759.             not_ready = x == -1;
  760.         }
  761.     } while(not_ready);
  762.  
  763.     if(using_combios){
  764.         inregs.h.ah = 2;    /* read character */
  765.         int86(0x14,&inregs,&outregs);
  766.         return outregs.h.al;
  767.     }
  768.     else{
  769.         return x & 0xff;
  770.     }
  771. }
  772.  
  773. /*
  774.     Print a 6 character mnemonic
  775. */
  776.  
  777. p_mnem(string)
  778. char *string;
  779. {
  780.     int i;
  781.  
  782.     for(i=0; i < 6; i++)
  783.         putchar(*string++);
  784. }
  785.  
  786. /*
  787.     Print IP datagram header
  788. */
  789.  
  790. do_ip()
  791. {
  792.     printf("IP frame\n");
  793. }
  794.  
  795. /*
  796.     Print ARP frame type
  797. */
  798.  
  799. do_arp()
  800. {
  801.     printf("ARP frame\n");
  802. }
  803.  
  804. /*
  805.     Locate entry in the statistics table for this circuit.  
  806.     Generate a new entry if the circuit doesn't exist.
  807. */
  808.  
  809. find_circuit(from,to)
  810. char *from;
  811. char *to;
  812. {
  813.     int i;
  814.  
  815.     /* attempt to lookup existing circuit in table */
  816.  
  817.     for(i=0; i < nr_circuits; i++){
  818.         if(!strcmp(ctab[i].to,to) && !strcmp(ctab[i].from,from)){
  819.             cnum = i;
  820.             return;
  821.         }
  822.     }
  823.  
  824.     /* check for table overflow */
  825.  
  826.     if(i == MAX_CIRCUIT){
  827.         dump_data();    
  828.         err_exit("The circuit table is full!");
  829.     }
  830.  
  831.     /* initialize new table entry */
  832.  
  833.     nr_circuits++;
  834.     memset(&ctab[i],'\0',sizeof(struct CIRCUIT_RECORD));
  835.     memset(&stab[i],'\0',sizeof(struct STATE_TABLE));
  836.     strcpy(ctab[i].to,to);
  837.     strcpy(ctab[i].from,from);
  838.     ctab[i].digis = nr_digi;
  839.     time(&ctab[i].c_time);        /* timestamp entry */
  840.     stab[i].last_s = 0;        /* impossible sup type */
  841.     cnum = i;
  842. }    
  843.  
  844. /*
  845.     Compute size of data portion of I or UI frame types.
  846.     Calculate Checksum on data portion.
  847. */
  848.  
  849. do_i_size()
  850. {
  851.     unsigned char *tmp;
  852.     int x;
  853.     
  854.     /* cp is currently pointing at the frames control byte */
  855.  
  856.     i_size = frame_size - (cp - &frame_buf[1]) - 4;
  857.  
  858.     /* calculate checksum of data portion of the frame */
  859.  
  860.     isum = 0;
  861.     tmp = cp;
  862.     x = i_size + 1;
  863.     tmp++;         /* point to pid byte */
  864.  
  865.     /* calculate checksum of I portion of frame */
  866.  
  867.     while(x--){
  868.         isum += *tmp++;
  869.     }
  870. }
  871.  
  872. /*
  873.     Dump the statistic tables to disk
  874. */
  875.  
  876. dump_data()
  877. {
  878.     int i;
  879.     FILE *fp;
  880.  
  881.     freq.dcd_on_ticks = get_cd_active();
  882.     freq.dcd_off_ticks = get_cd_inactive();
  883.  
  884.     if(!(fp = fopen("LOG","a")))
  885.         err_exit("Opening LOG file.");
  886.  
  887.     fprintf(fp,"T,%lu\n",start_time);
  888.  
  889.     fprintf(fp,"F,%lu,%lu,%lu,",freq.t_packets,freq.t_bytes,freq.u_packets);
  890.     fprintf(fp,"%lu,%lu,%lu,",freq.u_bytes,freq.l32,freq.l64);
  891.     fprintf(fp,"%lu,%lu,%lu,",freq.l128,freq.l256,freq.g256);
  892.     fprintf(fp,"%lu,%lu\n",freq.dcd_on_ticks,freq.dcd_off_ticks);
  893.     printf("\n\n     { Opening log file at %s",ctime(&start_time));
  894.     printf("      Writing %d digipeater records...",nr_digis);
  895.     for(i=0; i < nr_digis; i++){
  896.         fprintf(fp,"D,%s,%lu,",dtab[i].call,dtab[i].t_packets);
  897.         fprintf(fp,"%lu\n",dtab[i].t_bytes);
  898.     }
  899.     printf("\n      Writing %d circuit records...",nr_circuits);
  900.     for(i=0; i < nr_circuits; i++){
  901.         fprintf(fp,"C,%s,%s,%d,",ctab[i].to,ctab[i].from,ctab[i].digis);
  902.         fprintf(fp,"%d,",ctab[i].pid);
  903.         fprintf(fp,"%lu,%lu,",ctab[i].u_dpackets,ctab[i].nd_dpackets);
  904.         fprintf(fp,"%lu,%lu,",ctab[i].t_dpackets,ctab[i].nd_packets);
  905.         fprintf(fp,"%lu,%lu,",ctab[i].t_packets,ctab[i].u_dbytes);
  906.         fprintf(fp,"%lu,",ctab[i].nd_dbytes);
  907.         fprintf(fp,"%lu,%lu,",ctab[i].t_dbytes,ctab[i].nd_bytes);
  908.         fprintf(fp,"%lu,",ctab[i].t_bytes);
  909.         fprintf(fp,"%lu,",ctab[i].c_time);
  910.         fprintf(fp,"%lu,%lu,%lu,",ctab[i].sabm,ctab[i].ua,ctab[i].disc);
  911.         fprintf(fp,"%lu,%lu,%lu,",ctab[i].dm,ctab[i].rej,ctab[i].rr);
  912.         fprintf(fp,"%lu,%lu,",ctab[i].rnr,ctab[i].i);
  913.         fprintf(fp,"%lu,%lu,",ctab[i].ui,ctab[i].frmr);
  914.         fprintf(fp,"%lu,%lu,%lu,",ctab[i].poll,ctab[i].final,ctab[i].l32);
  915.         fprintf(fp,"%lu,%lu,%lu,",ctab[i].l64,ctab[i].l128,ctab[i].l256);
  916.         fprintf(fp,"%lu\n",ctab[i].g256);
  917.     }
  918.     printf("\n      Closing LOG file...}");
  919.     if(fclose(fp))
  920.         err_exit("Closing LOG file.");
  921.     printf("\n");
  922.     init_freq();
  923.     time(&start_time);
  924.     write_time = start_time + DUMP_INTERVAL;
  925. }
  926.  
  927. /*
  928.     Build an ASCII callsign from left shifted AX.25 format
  929.     callsign.
  930. */
  931.  
  932. bcall(from,to)
  933. unsigned char *from;
  934. unsigned char *to;
  935. {
  936.     int i;
  937.     unsigned char c,*tmp;
  938.  
  939.     tmp = to;
  940.     for(i=0; i < 6; i++){
  941.         c = *from++ >> 1;
  942.         if(c != ' ')
  943.             *to++ = c;
  944.     }
  945.  
  946.     if(tmp == to){
  947.         sprintf(to,"BLANK");
  948.     }
  949.     else{
  950.         c = (*from >>1) & 0xf;
  951.  
  952.         if(c)
  953.             sprintf(to,"-%d",c);
  954.         else
  955.             *to = 0;
  956.     }
  957. }    
  958.  
  959. /*
  960.     Clear the frequency wide statistical counters.
  961. */
  962.  
  963. init_freq()
  964. {
  965.     freq.t_packets =
  966.     freq.t_bytes =
  967.     freq.u_packets =
  968.     freq.u_bytes =
  969.     freq.l32 =
  970.     freq.l64 =
  971.     freq.l128 =
  972.     freq.l256 =
  973.     freq.g256 = 0l;
  974.     nr_circuits = 
  975.     nr_digis = 0;
  976. }
  977.  
  978. /*
  979.     Gather statistics on Digipeater activity
  980. */
  981.  
  982. do_digi(dptr)
  983. unsigned char *dptr;
  984. {
  985.     int i;
  986.     unsigned char digi_call[10];
  987.  
  988.     bcall(dptr,digi_call);
  989.  
  990.     /* lookup digipeater callsign in digipeater table */
  991.  
  992.     for(i=0; i < nr_digis; i++){
  993.         if(!strcmp(dtab[i].call,digi_call)){
  994.             dtab[i].t_packets++;
  995.             dtab[i].t_bytes += frame_size;
  996.             return;
  997.         }
  998.     }
  999.  
  1000.     /* check for table overflow */
  1001.  
  1002.     if(i == MAX_DIGIS){
  1003.         printf("\007Error: The digipeater table is full!\n");
  1004.         return;
  1005.     }
  1006.  
  1007.     /* initialize new digipeater table entry */
  1008.  
  1009.     nr_digis++;
  1010.     strcpy(dtab[i].call,digi_call);
  1011.     dtab[i].t_packets = 1l;
  1012.     dtab[i].t_bytes = frame_size;
  1013. }
  1014.  
  1015. /*
  1016.     Print fatal error message, shutdown background interrupt
  1017.     processes and exit.
  1018. */
  1019.  
  1020. err_exit(string)
  1021. char *string;
  1022. {
  1023.     printf("\007Error: %s\n",string);
  1024.     if(!using_combios)
  1025.         serldone();
  1026.     tick_stop();
  1027.     exit();
  1028. }
  1029.  
  1030. /*
  1031.     Process keystrokes entered by user
  1032. */
  1033.  
  1034. do_kbhit()
  1035. {
  1036.     unsigned char kbdata;
  1037.     kbdata = getch();
  1038.     if(kbdata == 0){
  1039.         kbdata = getch();
  1040.         if (kbdata == 45/*X*/) {
  1041.  
  1042.             /* ALT-X - exit */
  1043.  
  1044.             if(ints_active)
  1045.                 serldone();
  1046.             tick_stop();
  1047.             dump_data();
  1048.             exit();
  1049.         }
  1050.         else if (kbdata == 46/*C*/) {
  1051.             cprintf("cmd:");
  1052.             parse(0,NULL);
  1053.         }
  1054.     }
  1055. }
  1056.  
  1057. /*
  1058.     Print Call in AX.25 left shifted format.  Add an
  1059.     '*' after call if it's an digipeater and the has been
  1060.     digipeated bit is set and the next digipeater's bit is
  1061.     not set.
  1062. */
  1063.  
  1064. pcall(string,flag)
  1065. unsigned char *string;
  1066. int flag;        /* set if call is a digipeater call */    
  1067. {
  1068.     int i;
  1069.     char c;
  1070.  
  1071.     /* print the callsign */
  1072.  
  1073.     for(i = 0; i< 6; i++){
  1074.         c=*string++ >> 1;
  1075.         if(c != ' ')
  1076.             putchar(c);
  1077.     }
  1078.  
  1079.     /* display SSID if there is one */
  1080.  
  1081.     c=(*string >> 1) & 0xf;
  1082.     if(c)
  1083.         printf("-%d",c);
  1084.  
  1085.     /* display the has been digipeated bit if appropriate */
  1086.  
  1087.     if (flag) {
  1088.         if(*string & 0x80 && (*string & 1 || !(string[7] & 0x80)))
  1089.             putchar('*');
  1090.     }
  1091. }
  1092.  
  1093. /*
  1094.     Process the digipeaters heard bit map, set the global retry flag
  1095.     if the frame has been heard from this hop before.
  1096. */
  1097.  
  1098. do_bitmap(bit_map)
  1099. unsigned int *bit_map;
  1100. {
  1101.     if(*bit_map & digi_bit){
  1102.  
  1103.         /* this digi was heard before, this must be a retry */
  1104.  
  1105.         *bit_map = digi_bit;    /* clear other bits */
  1106.         dnum = cnum;        /* increment nd counters */
  1107.         retry = TRUE;
  1108.     }
  1109.     else if(*bit_map){
  1110.  
  1111.         /* some other digi was heard, this must be another */
  1112.         /* digipeater hop, don't do nd counters           */
  1113.  
  1114.         *bit_map |= digi_bit;    /* set our bit */
  1115.         dnum = nr_circuits;    /* don't do nd counters, point */
  1116.                     /* dnum somewhere harmless     */
  1117.         retry = FALSE;
  1118.     }
  1119.     else{
  1120.         
  1121.         /* no one was heard from before, this must be */
  1122.         /* the first time this packet was heard          */
  1123.  
  1124.         *bit_map |= digi_bit;    /* set our bit */
  1125.         dnum = cnum;        /* increment nd counters */
  1126.         retry = FALSE;
  1127.     }
  1128. }
  1129. 
  1130.